home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Tool Chest / Development Tools & Languages / • Other Platforms / PCCTS / antlr / antlr.g < prev    next >
Encoding:
Text File  |  1994-09-14  |  34.2 KB  |  1,199 lines  |  [TEXT/MPS ]

  1. /*
  2.  * antlr.g    --    PCCTS Version 1.xx ANTLR
  3.  *
  4.  * $Id: antlr.g,v 1.10 1994/08/29 20:16:14 parrt Exp parrt $
  5.  * $Revision: 1.10 $
  6.  *
  7.  * Parse an antlr input grammar and build a syntax-diagram.
  8.  *
  9.  * Written in itself (needs at least 1.06 to work)
  10.  *
  11.  * SOFTWARE RIGHTS
  12.  *
  13.  * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
  14.  * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
  15.  * company may do whatever they wish with source code distributed with
  16.  * PCCTS or the code generated by PCCTS, including the incorporation of
  17.  * PCCTS, or its output, into commerical software.
  18.  * 
  19.  * We encourage users to develop software with PCCTS.  However, we do ask
  20.  * that credit is given to us for developing PCCTS.  By "credit",
  21.  * we mean that if you incorporate our source code into one of your
  22.  * programs (commercial product, research project, or otherwise) that you
  23.  * acknowledge this fact somewhere in the documentation, research report,
  24.  * etc...  If you like PCCTS and have developed a nice tool with the
  25.  * output, please mention that you developed it using PCCTS.  In
  26.  * addition, we ask that this header remain intact in our source code.
  27.  * As long as these guidelines are kept, we expect to continue enhancing
  28.  * this system and expect to make other tools available as they are
  29.  * completed.
  30.  *
  31.  * ANTLR 1.23
  32.  * Terence Parr
  33.  * Parr Research Corporation
  34.  * with Purdue University and AHPCRC, University of Minnesota
  35.  * 1989-1994
  36.  */
  37. #header <<
  38.     #ifdef __cplusplus
  39.     #ifndef __STDC__
  40.     #define __STDC__
  41.     #endif
  42.     #endif
  43.     #include "set.h"
  44.     #include <ctype.h>
  45.     #include "syn.h"
  46.     #include "hash.h"
  47.     #include "generic.h"
  48.     #define zzcr_attr(attr,tok,t)
  49.     >>
  50.  
  51. <<
  52. #ifdef __STDC__
  53. static void chkToken(char *, char *, char *, int);
  54. #else
  55. static void chkToken();
  56. #endif
  57.  
  58. static int class_nest_level = 0;
  59. >>
  60.  
  61. #lexaction <<
  62. /* maintained, but not used for now */
  63. set AST_nodes_refd_in_actions = set_init;
  64. >>
  65.  
  66. #lexclass STRINGS
  67. #token QuotedTerm "\""        << zzmode(START); >>
  68. #token "\n"                    <<
  69.                             zzline++;
  70.                             warn("eoln found in string");
  71.                             zzskip();
  72.                             >>
  73. #token "\\\n"                << zzline++; zzmore(); >>
  74. #token "\\~[]"                << zzmore(); >>
  75. #token "~[\n\"\\]+"            << zzmore(); >>
  76.  
  77. #lexclass ACTION_STRINGS
  78. #token "\""                    << zzmode(ACTIONS); zzmore(); >>
  79. #token "\n"                    <<
  80.                             zzline++;
  81.                             warn("eoln found in string (in user action)");
  82.                             zzskip();
  83.                             >>
  84. #token "\\\n"                << zzline++; zzmore(); >>
  85. #token "\\~[]"                << zzmore(); >>
  86. #token "~[\n\"\\]+"            << zzmore(); >>
  87.  
  88. #lexclass ACTION_CHARS
  89. #token "'"                    << zzmode(ACTIONS); zzmore(); >>
  90. #token "\n"                    <<
  91.                             zzline++;
  92.                             warn("eoln found in char literal (in user action)");
  93.                             zzskip();
  94.                             >>
  95. #token "\\~[]"                << zzmore(); >>
  96. #token "~[\n'\\]+"            << zzmore(); >>
  97.  
  98. #lexclass ACTION_COMMENTS
  99. #token "\*/"                << zzmode(ACTIONS); zzmore(); >>
  100. #token "\*"                    << zzmore(); >>
  101. #token "\n"                    << zzline++; zzmore(); DAWDLE; >>
  102. #token "~[\n\*]+"            << zzmore(); >>
  103.  
  104. #lexclass TOK_DEF_COMMENTS
  105. #token "\*/"                << zzmode(PARSE_ENUM_FILE); zzmore(); >>
  106. #token "\*"                    << zzmore(); >>
  107. #token "\n"                    << zzline++; zzmore(); DAWDLE; >>
  108. #token "~[\n\*]+"            << zzmore(); >>
  109.  
  110. #lexclass TOK_DEF_CPP_COMMENTS
  111. #token "\n"                    << zzline++; zzmode(PARSE_ENUM_FILE); zzmore(); DAWDLE; >>
  112. #token "~[\n]+"                << zzmore(); >>
  113.  
  114. #lexclass ACTION_CPP_COMMENTS
  115. #token "\n"                    << zzline++; zzmode(ACTIONS); zzmore(); DAWDLE; >>
  116. #token "~[\n]+"                << zzmore(); >>
  117.  
  118. #lexclass CPP_COMMENTS
  119. #token "\n"                    << zzline++; zzmode(START); zzskip(); DAWDLE; >>
  120. #token "~[\n]+"                << zzskip(); >>
  121.  
  122. #lexclass COMMENTS
  123. #token "\*/"                << zzmode(START); zzskip(); >>
  124. #token "\*"                    << zzskip(); >>
  125. #token "\n"                    << zzline++; zzskip(); DAWDLE; >>
  126. #token "~[\n\*]+"            << zzskip(); >>
  127.  
  128. /*
  129.  * This lexical class accepts actions of type [..] and <<..>>
  130.  *
  131.  * It translates the following special items for C:
  132.  *
  133.  * $j        --> "zzaArg(current zztasp, j)"
  134.  * $i.j        --> "zzaArg(zztaspi, j)"
  135.  * $i.nondigit> "zzaArg(current zztasp, i).nondigit"
  136.  * $$        --> "zzaRet"
  137.  * $alnum    --> "alnum"            (used to ref parameters)
  138.  * $rule    --> "zzaRet"
  139.  * $retval    --> "_retv.retval" if > 1 return values else "_retv"
  140.  * $[token, text] --> "zzconstr_attr(token, text)"
  141.  * $[]        --> "zzempty_attr()"
  142.  *
  143.  * It translates the following special items for C++:
  144.  * (attributes are now stored with 'Token' and $i's are only 
  145.  *  pointers to the Tokens.  Rules don't have attributes now.)
  146.  *
  147.  * $j        --> "_tbj" where b is the block level
  148.  * $i.j        --> "_tij"
  149.  * $j->nondigit> "_tbj->nondigit"
  150.  * $$        --> "$$"
  151.  * $alnum    --> "alnum"            (used to ref parameters)
  152.  * $rule    --> "$rule"
  153.  * $retval    --> "_retv.retval" if > 1 return values else "_retv"
  154.  * $[token, text] --> invalid
  155.  * $[]        --> invalid
  156.  *
  157.  * And, for trees:
  158.  *
  159.  * #0        -->    "(*_root)"
  160.  * #i        --> "zzastArg(i)"
  161.  * #[args]    --> "zzmk_ast(zzastnew(), args)"
  162.  * #[]        --> "zzastnew()"
  163.  * #( root, child1, ..., childn )
  164.             --> "zztmake(root, child1, ...., childn, NULL)"
  165.  * #()        --> "NULL"
  166.  *
  167.  * For C++, ...
  168.  *
  169.  * #0        -->    "(*_root)"
  170.  * #i        --> "_astbi" where b is the block level
  171.  * #[args]    --> "new AST(args)"
  172.  * #[]        --> "new AST"
  173.  * #( root, child1, ..., childn )
  174.             --> "AST::tmake(root, child1, ...., childn, NULL)"
  175.  * #()        --> "NULL"
  176.  *
  177.  * To escape,
  178.  *
  179.  * \]        --> ]
  180.  * \)        --> )
  181.  * \$        --> $
  182.  * \#        --> #
  183.  *
  184.  * A stack is used to nest action terminators because they can be nested
  185.  * like crazy:  << #[$[..],..] >>
  186.  */
  187. #lexclass ACTIONS
  188. #token Action "\>\>"        << /* these do not nest */
  189.                               zzmode(START);
  190.                               NLATEXT[0] = ' ';
  191.                               NLATEXT[1] = ' ';
  192.                               zzbegexpr[0] = ' ';
  193.                               zzbegexpr[1] = ' ';
  194.                               if ( zzbufovf ) {
  195.                                 err( eMsgd("action buffer overflow; size %d",ZZLEXBUFSIZE));
  196.                               }
  197.                             >>
  198. #token Pred "\>\>?"            << /* these do not nest */
  199.                               zzmode(START);
  200.                               NLATEXT[0] = ' ';
  201.                               NLATEXT[1] = ' ';
  202.                               zzbegexpr[0] = '\0';
  203.                               if ( zzbufovf ) {
  204.                                 err( eMsgd("predicate buffer overflow; size %d",ZZLEXBUFSIZE));
  205.                               }
  206.                             >>
  207. #token PassAction "\]"        << if ( topint() == ']' ) {
  208.                                   popint();
  209.                                   if ( istackempty() )    /* terminate action */
  210.                                   {
  211.                                       zzmode(START);
  212.                                       NLATEXT[0] = ' ';
  213.                                       zzbegexpr[0] = ' ';
  214.                                       if ( zzbufovf ) {
  215.                                         err( eMsgd("parameter buffer overflow; size %d",ZZLEXBUFSIZE));
  216.                                       }
  217.                                   }
  218.                                   else {
  219.                                       /* terminate $[..] and #[..] */
  220.                                       if ( GenCC ) zzreplstr("))");
  221.                                       else zzreplstr(")");
  222.                                       zzmore();
  223.                                   }
  224.                                }
  225.                                else if ( topint() == '|' ) { /* end of simple [...] */
  226.                                   popint();
  227.                                   zzmore();
  228.                                }
  229.                                else zzmore();
  230.                             >>
  231. #token "\n"                    << zzline++; zzmore(); DAWDLE; >>
  232. #token "\>"                    << zzmore(); >>
  233. #token "$"                    << zzmore(); >>
  234. #token "$$"                    << if ( !GenCC ) {zzreplstr("zzaRet"); zzmore();}
  235.                                else err("$$ use invalid in C++ mode"); >>
  236.  
  237. #token "$\[\]"                << if ( !GenCC ) {zzreplstr("zzempty_attr"); zzmore();}
  238.                                else err("$[] use invalid in C++ mode"); >>
  239. #token "$\["                <<
  240.                             pushint(']');
  241.                             if ( !GenCC ) zzreplstr("zzconstr_attr(");
  242.                             else err("$[..] use invalid in C++ mode");
  243.                             zzmore();
  244.                             >>
  245. #token "$[0-9]+"            <<{
  246.                             static char buf[100];
  247.                             if ( strlen(zzbegexpr)>85 )
  248.                                 fatal("$i attrib ref too big");
  249.                             if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%d,%s)",
  250.                                         BlkLevel-1,zzbegexpr+1);
  251.                             else sprintf(buf,"_t%d%s",
  252.                                         BlkLevel-1,zzbegexpr+1);
  253.                             zzreplstr(buf);
  254.                             zzmore();
  255.                             }
  256.                             >>
  257. #token "$[0-9]+."            <<{
  258.                             static char buf[100];
  259.                             if ( strlen(zzbegexpr)>85 )
  260.                                 fatal("$i.field attrib ref too big");
  261.                             zzbegexpr[strlen(zzbegexpr)-1] = ' ';
  262.                             if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%d,%s).",
  263.                                         BlkLevel-1,zzbegexpr+1);
  264.                             else sprintf(buf,"_t%d%s.",
  265.                                         BlkLevel-1,zzbegexpr+1);
  266.                             zzreplstr(buf);
  267.                             zzmore();
  268.                             }
  269.                             >>
  270. #token "$[0-9]+.[0-9]+"        <<{
  271.                             static char buf[100];
  272.                             static char i[20], j[20];
  273.                             char *p,*q;
  274.                             if (strlen(zzbegexpr)>85) fatal("$i.j attrib ref too big");
  275.                             for (p=zzbegexpr+1,q= &i[0]; *p!='.'; p++) {
  276.                                 if ( q == &i[20] ) fatalFL("i of $i.j attrib ref too big", FileStr[CurFile], zzline );
  277.                                 *q++ = *p;
  278.                             }
  279.                             *q = '\0';
  280.                             for (p++, q= &j[0]; *p!='\0'; p++) {
  281.                                 if ( q == &j[20] ) fatalFL("j of $i.j attrib ref too big", FileStr[CurFile], zzline );
  282.                                 *q++ = *p;
  283.                             }
  284.                             *q = '\0';
  285.                             if ( !GenCC ) sprintf(buf,"zzaArg(zztasp%s,%s)",i,j);
  286.                             else sprintf(buf,"_t%s%s",i,j);
  287.                             zzreplstr(buf);
  288.                             zzmore();
  289.                             }
  290.                             >>
  291. #token "$[_a-zA-Z][_a-zA-Z0-9]*"
  292.                             <<{ static char buf[300];
  293.                             zzbegexpr[0] = ' ';
  294.                             if ( CurRule != NULL &&
  295.                                  strcmp(CurRule, &zzbegexpr[1])==0 ) {
  296.                                 if ( !GenCC ) zzreplstr("zzaRet");
  297.                             }
  298.                             else if ( CurRetDef != NULL ) {
  299.                                 if ( strmember(CurRetDef, &zzbegexpr[1]) ) {
  300.                                     if ( HasComma( CurRetDef ) ) {
  301.                                         require (strlen(zzbegexpr)<=285,
  302.                                                  "$retval attrib ref too big");
  303.                                         sprintf(buf,"_retv.%s",&zzbegexpr[1]);
  304.                                         zzreplstr(buf);
  305.                                     }
  306.                                     else zzreplstr("_retv");
  307.                                 }
  308.                                 else if ( CurParmDef != NULL ) {
  309.                                     if ( !strmember(CurParmDef, &zzbegexpr[1]) )
  310.                                         warn(eMsg1("$%s not parameter or return value",&zzbegexpr[1]));
  311.                                 }
  312.                                 else warn(eMsg1("$%s not parameter or return value",&zzbegexpr[1]));
  313.                             }
  314.                             }
  315.                             zzmore();
  316.                             >>
  317. #token "#0"                    << zzreplstr("(*_root)"); zzmore(); >>
  318. #token "#\[\]"                << if ( GenCC ) zzreplstr("(new AST)");
  319.                                zzreplstr("zzastnew()"); zzmore();>>
  320. #token "#\(\)"                << zzreplstr("NULL"); zzmore(); >>
  321. #token "#[0-9]+"            <<{
  322.                             static char buf[100];
  323.                             if ( strlen(zzbegexpr)>85 )
  324.                                 fatal("#i AST ref too big");
  325.                             if ( GenCC ) sprintf(buf,"_ast%d%s",BlkLevel-1,zzbegexpr+1);
  326.                             else sprintf(buf,"zzastArg(%s)",zzbegexpr+1);
  327.                             zzreplstr(buf);
  328.                             zzmore();
  329.                             set_orel(atoi(zzbegexpr+1), &AST_nodes_refd_in_actions);
  330.                             }
  331.                             >>
  332. #token "#\["                <<
  333.                             pushint(']');
  334.                             if ( GenCC ) zzreplstr("(new AST(");
  335.                             else zzreplstr("zzmk_ast(zzastnew(),");
  336.                             zzmore();
  337.                             >>
  338. #token "#\("                <<
  339.                             pushint('}');
  340.                             if ( GenCC ) zzreplstr("ASTBase::tmake(");
  341.                             else zzreplstr("zztmake(");
  342.                             zzmore();
  343.                             >>
  344. #token "#"                    << zzmore(); >>
  345. #token "\)"                    <<
  346.                             if ( istackempty() )
  347.                                 zzmore();
  348.                             else if ( topint()==')' ) {
  349.                                 popint();
  350.                             }
  351.                             else if ( topint()=='}' ) {
  352.                                 popint();
  353.                                 /* terminate #(..) */
  354.                                 zzreplstr(", NULL)");
  355.                             }
  356.                             zzmore();
  357.                             >>
  358. #token "\["                    <<
  359.                             pushint('|');    /* look for '|' to terminate simple [...] */
  360.                             zzmore();
  361.                             >>
  362. #token "\("                    <<
  363.                             pushint(')');
  364.                             zzmore();
  365.                             >>
  366.  
  367. #token "\\\]"                << zzreplstr("]");  zzmore(); >>
  368. #token "\\\)"                << zzreplstr(")");  zzmore(); >>
  369. #token "\\>"                << zzreplstr(">");  zzmore(); >>
  370.  
  371.  
  372. #token "'"                    << zzmode(ACTION_CHARS); zzmore();>>
  373. #token "\""                    << zzmode(ACTION_STRINGS); zzmore();>>
  374. #token "\\$"                << zzreplstr("$");  zzmore(); >>
  375. #token "\\#"                << zzreplstr("#");  zzmore(); >>
  376. #token "\\\n"                << zzline++; zzmore(); >>
  377. #token "\\~[\]\)>$#]"        << zzmore(); >> /* escaped char, always ignore */
  378. #token "/"                    << zzmore(); >>
  379. #token "/\*"                << zzmode(ACTION_COMMENTS); zzmore(); >>
  380. #token "\*/"                << warn("Missing /*; found dangling */ in action"); zzmore(); >>
  381. #token "//"                    << zzmode(ACTION_CPP_COMMENTS); zzmore(); >>
  382. #token "~[\n\)\(\\$#\>\]\[\"'/]+" << zzmore(); >>
  383.  
  384. #lexclass START
  385. #token "[\t\ ]+"            << zzskip(); >>                /* Ignore White */
  386. #token "[\n\r]"                << zzline++; zzskip(); >>    /* Track Line # */
  387. #token "\["                 << zzmode(ACTIONS); zzmore();
  388.                                istackreset();
  389.                                pushint(']'); >>
  390. #token "\<\<"               << action_file=CurFile; action_line=zzline;
  391.                                zzmode(ACTIONS); zzmore();
  392.                                istackreset();
  393.                                pushint('>'); >>
  394. #token "\""                    << zzmode(STRINGS); zzmore(); >>
  395. #token "/\*"                << zzmode(COMMENTS); zzskip(); >>
  396. #token "\*/"                << warn("Missing /*; found dangling */"); zzskip(); >>
  397. #token "//"                    << zzmode(CPP_COMMENTS); zzskip(); >>
  398. #token "\>\>"                << warn("Missing <<; found dangling \\>\\>"); zzskip(); >>
  399. #token WildCard "."
  400. #token Eof                    "@"
  401.                             <<    /* L o o k  F o r  A n o t h e r  F i l e */
  402.                             {
  403.                             FILE *new_input;
  404.                             new_input = NextFile();
  405.                             if ( new_input == NULL ) { NLA=Eof; return; }
  406.                             fclose( input );
  407.                             input = new_input;
  408.                             zzrdstream( input );
  409.                             zzskip();    /* Skip the Eof (@) char i.e continue */
  410.                             }
  411.                             >>
  412.  
  413. #errclass "grammar-element" { element }
  414. #errclass "meta-symbol"        { "\}" "!" ";" "\|" "\~" "^" "\)" }
  415.  
  416. /*
  417.  * Get a grammar -- Build a list of rules like:
  418.  *
  419.  *    o-->Rule1--o
  420.  *    |
  421.  *    o-->Rule2--o
  422.  *    |
  423.  *    ...
  424.  *    |
  425.  *    o-->RuleN--o
  426.  */
  427. grammar :    <<Graph g;>>
  428.             (    "#header" Action
  429.                 <<
  430.                 if ( HdrAction==NULL ) {
  431.                 HdrAction = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  432.                 require(HdrAction!=NULL, "rule grammar: cannot allocate header action");
  433.                 strcpy(HdrAction, LATEXT(1));
  434.                 }
  435.                 else warn("additional #header statement ignored");
  436.                 >>
  437.             |    "#parser" QuotedTerm
  438.                 <<
  439.                 if ( GenCC ) {
  440.                     warn("#parser meta-op incompatible with -CC; ignored");
  441.                 }
  442.                 else {
  443.                     if ( strcmp(ParserName,"zzparser")==0 ) {
  444.                         ParserName=StripQuotes(mystrdup(LATEXT(1)));
  445.                         if ( RulePrefix[0]!='\0' )
  446.                         {
  447.                             warn("#parser meta-op incompatible with '-gp prefix'; '-gp' ignored");
  448.                             RulePrefix[0]='\0';
  449.                         }
  450.                     }
  451.                     else warn("additional #parser statement ignored");
  452.                 }
  453.                 >>
  454.             |    "#tokdefs" QuotedTerm
  455.                 <<{
  456.                 char *fname;
  457.                 zzantlr_state st; FILE *f; struct zzdlg_state dst;
  458.                 UserTokenDefsFile = mystrdup(LATEXT(1));
  459.                 zzsave_antlr_state(&st);
  460.                 zzsave_dlg_state(&dst);
  461.                 fname = mystrdup(LATEXT(1));
  462.                 f = fopen(StripQuotes(fname), "r");
  463.                 if ( f==NULL ) {warn(eMsg1("cannot open token defs file '%s'", fname+1));}
  464.                 else {
  465.                     ANTLRm(enum_file(fname+1), f, PARSE_ENUM_FILE);
  466.                     UserDefdTokens = 1;
  467.                 }
  468.                 zzrestore_antlr_state(&st);
  469.                 zzrestore_dlg_state(&dst);
  470.                 }>>
  471.             )*
  472.             (    Action
  473.                 <<{
  474.                 UserAction *ua = newUserAction(LATEXT(1));
  475.                 ua->file = action_file; ua->line = action_line;
  476.                 if ( class_nest_level>0 ) list_add(&class_actions, ua);
  477.                 else list_add(&BeforeActions, ua);
  478.                 }>>
  479.             |    laction
  480.             |    aLexclass
  481.             |    token
  482.             |    error
  483.             |    tclass
  484.             |    class_def
  485.             |    "\}"
  486.                 <<
  487.                 if ( class_nest_level==0 )
  488.                     warn("missing class definition for trailing '}'");
  489.                 class_nest_level--;
  490.                 >>
  491.             )*
  492.             rule        <<g=$3; SynDiag = (Junction *) $3.left;>>
  493.             (    rule    <<if ( $1.left!=NULL ) {g.right = NULL; g = Or(g, $1);}>>
  494.             |    aLexclass
  495.             |    token
  496.             |    error
  497.             |    tclass
  498.             |    class_def
  499.             |    "\}"
  500.                 <<
  501.                 if ( class_nest_level==0 )
  502.                     warn("missing class definition for trailing '}'");
  503.                 class_nest_level--;
  504.                 >>
  505.             )*
  506.             (    Action
  507.                 <<{
  508.                 UserAction *ua = newUserAction(LATEXT(1));
  509.                 ua->file = action_file; ua->line = action_line;
  510.                 if ( class_nest_level>0 ) list_add(&class_actions, ua);
  511.                 else list_add(&AfterActions, ua);
  512.                 }>>
  513.             |    laction
  514.             |    error
  515.             |    tclass
  516.             |    class_def
  517.             |    "\}"
  518.                 <<
  519.                 if ( class_nest_level==0 )
  520.                     warn("missing class definition for trailing '}'");
  521.                 class_nest_level--;
  522.                 >>
  523.             )*
  524.             Eof
  525.         ;
  526.         <<CannotContinue=TRUE;>>
  527.  
  528. class_def
  529.     :    <<int go=1; char name[MaxRuleName+1];>>
  530.         "class"
  531.         (    NonTerminal        <<if(go) strncpy(name,LATEXT(1),MaxRuleName);>>
  532.         |    TokenTerm        <<if(go) strncpy(name,LATEXT(1),MaxRuleName);>>
  533.         )
  534.         <<
  535.         if ( CurrentClassName[0]!='\0' && strcmp(CurrentClassName,name)!=0
  536.              && GenCC ) {
  537.             err("only one grammar class allowed in this release");
  538.             go = 0;
  539.         }
  540.         else strcpy(CurrentClassName, name);
  541.         >>
  542.         <<if ( !GenCC ) { err("class meta-op used without C++ option"); }>>
  543.         "\{"
  544.         <<
  545.         no_classes_found = 0;
  546.         if ( class_nest_level>=1 ) {warn("cannot have nested classes");}
  547.         else class_nest_level++;
  548.         >>
  549.     ;
  550.     <<CannotContinue=TRUE;>>
  551.  
  552. /*
  553.  * Build -o-->o-R-o-->o-    where -o-R-o- is the block from rule 'block'.
  554.  * Construct the RuleBlk front and EndRule node on the end of the
  555.  * block.  This is used to add FOLLOW pointers to the rule end.  Add the
  556.  * new rule name to the Rname hash table and sets its rulenum.
  557.  * Store the parameter definitions if any are found.
  558.  *
  559.  * Note that locks are required on the RuleBlk and EndRule nodes to thwart
  560.  * infinite recursion.
  561.  *
  562.  * Return the left graph pointer == NULL to indicate error/dupl rule def.
  563.  */
  564. rule    :    <<
  565.             RuleEntry *q; Junction *p; Graph r; int f, l; ECnode *e;
  566.             set toksrefd, rulesrefd;
  567.             char *pdecl=NULL, *ret=NULL, *a; CurRetDef = CurParmDef = NULL;
  568.             >>
  569.             NonTerminal
  570.             <<q=NULL;
  571.               if ( hash_get(Rname, LATEXT(1))!=NULL ) {
  572.                   warn(eMsg1("duplicate rule definition: '%s'",LATEXT(1)));
  573.                   CannotContinue=TRUE;
  574.               }
  575.               else
  576.               {
  577.                     q = (RuleEntry *)hash_add(Rname,
  578.                                         LATEXT(1),
  579.                                         (Entry *)newRuleEntry(LATEXT(1)));
  580.                   CurRule = q->str;
  581.               }
  582.               CurRuleNode = q;
  583.               f = CurFile; l = zzline;
  584.               NumRules++;
  585.             >>
  586.             {    "!"  <<if ( q!=NULL ) q->noAST = TRUE;>> }
  587.             {    <<;>>
  588.                 {"\<"}
  589.                 PassAction
  590.                 <<    pdecl = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  591.                     require(pdecl!=NULL, "rule rule: cannot allocate param decl");
  592.                     strcpy(pdecl, LATEXT(1));
  593.                     CurParmDef = pdecl;
  594.                 >>
  595.             }
  596.             {    "\>"
  597.                 PassAction
  598.                 <<    ret = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  599.                     require(ret!=NULL, "rule rule: cannot allocate ret type");
  600.                     strcpy(ret, LATEXT(1));
  601.                      CurRetDef = ret;
  602.                 >>
  603.             }
  604.             { QuotedTerm <<if ( q!=NULL ) q->egroup=mystrdup(LATEXT(1));>> }
  605.             <<
  606.             if ( GenEClasseForRules && q!=NULL ) {
  607.                 e = newECnode;
  608.                 require(e!=NULL, "cannot allocate error class node");
  609.                 if ( q->egroup == NULL ) {a = q->str; a[0] = (char)toupper(a[0]);}
  610.                 else a = q->egroup;
  611.                 if ( Tnum( a ) == 0 )
  612.                 {
  613.                     e->tok = addTname( a );
  614.                     list_add(&eclasses, (char *)e);
  615.                     if ( q->egroup == NULL ) a[0] = (char)tolower(a[0]);
  616.                     /* refers to itself */
  617.                     list_add(&(e->elist), mystrdup(q->str));
  618.                 }
  619.                 else {
  620.                     warn(eMsg1("default errclass for '%s' would conflict with token/errclass/tokclass",a));
  621.                     if ( q->egroup == NULL ) a[0] = (char)tolower(a[0]);
  622.                     free((char *)e);
  623.                 }
  624.             }
  625.             >>
  626.             <<BlkLevel++;>>
  627.             ":" block[&toksrefd, &rulesrefd]
  628.                             <<r = makeBlk($7,0);
  629.                               ((Junction *)r.left)->jtype = RuleBlk;
  630.                               if ( q!=NULL ) ((Junction *)r.left)->rname = q->str;
  631.                               ((Junction *)r.left)->file = f;
  632.                               ((Junction *)r.left)->line = l;
  633.                               ((Junction *)r.left)->pdecl = pdecl;
  634.                               ((Junction *)r.left)->ret = ret;
  635.                               ((Junction *)r.left)->lock = makelocks();
  636.                               ((Junction *)r.left)->pred_lock = makelocks();
  637.                               ((Junction *)r.left)->tokrefs = toksrefd;
  638.                               ((Junction *)r.left)->rulerefs = rulesrefd;
  639.                               p = newJunction();    /* add EndRule Node */
  640.                               ((Junction *)r.right)->p1 = (Node *)p;
  641.                               r.right = (Node *) p;
  642.                               p->jtype = EndRule;
  643.                               p->lock = makelocks();
  644.                               p->pred_lock = makelocks();
  645.                               ((Junction *)r.left)->end = p;
  646.                               if ( q!=NULL ) q->rulenum = NumRules;
  647.                               $7 = r;
  648.                             >>
  649.             <<--BlkLevel;>>
  650.             ";"
  651.             {    Action
  652.                 <<    a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  653.                     require(a!=NULL, "rule rule: cannot allocate error action");
  654.                     strcpy(a, LATEXT(1));
  655.                     ((Junction *)r.left)->erraction = a;
  656.                 >>
  657.             }
  658.             <<if ( q==NULL ) $0.left = NULL; else $0 = $7;>>
  659.             <<CurRuleNode = NULL;>>
  660.         ;
  661.         <<CannotContinue=TRUE;>>
  662.  
  663. laction    :    <<char *a;>>
  664.             "#lexaction"
  665.             Action
  666.             <<
  667.             a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  668.             require(a!=NULL, "rule laction: cannot allocate action");
  669.             strcpy(a, LATEXT(1));
  670.             list_add(&LexActions, a);
  671.             >>
  672.         ;
  673.         <<CannotContinue=TRUE;>>
  674.  
  675. aLexclass:    "#lexclass" TokenTerm <<lexclass(mystrdup(LATEXT(1)));>>
  676.         ;
  677.         <<CannotContinue=TRUE;>>
  678.  
  679. error    :    <<char *t=NULL; ECnode *e; int go=1; TermEntry *p;>>
  680.             "#errclass"
  681.             (<<;>>    TokenTerm  <<t=mystrdup(LATEXT(1));>>
  682.             |        QuotedTerm <<t=mystrdup(LATEXT(1));>>
  683.             )
  684.             <<e = newECnode;
  685.               require(e!=NULL, "cannot allocate error class node");
  686.               e->lexclass = CurrentLexClass;
  687.               if ( Tnum( (t=StripQuotes(t)) ) == 0 )
  688.               {
  689.                 if ( hash_get(Texpr, t) != NULL )
  690.                     warn(eMsg1("errclass name conflicts with regular expression  '%s'",t));
  691.                   e->tok = addTname( t );
  692.                 set_orel(e->tok, &imag_tokens);
  693.                 require((p=(TermEntry *)hash_get(Tname, t)) != NULL,
  694.                         "hash table mechanism is broken");
  695.                 p->classname = 1;    /* entry is errclass name, not token */
  696.                 list_add(&eclasses, (char *)e);
  697.               }
  698.               else
  699.               {
  700.                   warn(eMsg1("redefinition of errclass or conflict w/token or tokclass '%s'; ignored",t));
  701.                 free( (char *)e );
  702.                 go=0;
  703.               }
  704.             >>
  705.             "\{"
  706.                 ( NonTerminal <<if ( go ) t=mystrdup(LATEXT(1));>>
  707.                 | TokenTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  708.                 | QuotedTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  709.                 )
  710.                 <<if ( go ) list_add(&(e->elist), t);>>
  711.                 (
  712.                     ( NonTerminal <<if ( go ) t=mystrdup(LATEXT(1));>>
  713.                     | TokenTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  714.                     | QuotedTerm <<if ( go ) t=mystrdup(LATEXT(1));>>
  715.                     )
  716.                     <<if ( go ) list_add(&(e->elist), t);>>
  717.                 )*
  718.             "\}"
  719.         ;
  720.         <<CannotContinue=TRUE;>>
  721.  
  722. tclass    :    <<char *t=NULL; TCnode *e; int go=1,tok; TermEntry *p, *term;>>
  723.             "#tokclass" TokenTerm <<t=mystrdup(LATEXT(1));>>
  724.             <<e = newTCnode;
  725.               require(e!=NULL, "cannot allocate token class node");
  726.               e->lexclass = CurrentLexClass;
  727.               if ( Tnum( t ) == 0 )
  728.               {
  729.                   e->tok = addTname( t );
  730.                 set_orel(e->tok, &imag_tokens);
  731.                 require((p=(TermEntry *)hash_get(Tname, t)) != NULL,
  732.                         "hash table mechanism is broken");
  733.                 p->classname = 1;    /* entry is class name, not token */
  734.                 p->tclass = e;        /* save ptr to this tclass def */
  735.                 list_add(&tclasses, (char *)e);
  736.               }
  737.               else
  738.               {
  739.                   warn(eMsg1("redefinition of tokclass or conflict w/token '%s'; ignored",t));
  740.                 free( (char *)e );
  741.                 go=0;
  742.               }
  743.             >>
  744.             "\{"
  745.                 (
  746.                 ( TokenTerm
  747.                   <<if ( go ) {
  748.                     term = (TermEntry *) hash_get(Tname, LATEXT(1));
  749.                     if ( term==NULL && UserDefdTokens ) {
  750.                         err("implicit token definition not allowed with #tokdefs");
  751.                         go = 0;
  752.                     }
  753.                     else {t=mystrdup(LATEXT(1)); tok=addTname(LATEXT(1));}
  754.                     }>>
  755.                 | QuotedTerm
  756.                   <<if ( go ) {
  757.                     term = (TermEntry *) hash_get(Texpr, LATEXT(1));
  758.                     if ( term==NULL && UserDefdTokens ) {
  759.                         err("implicit token definition not allowed with #tokdefs");
  760.                         go = 0;
  761.                     }
  762.                     else {t=mystrdup(LATEXT(1)); tok=addTexpr(LATEXT(1));}
  763.                     }>>
  764.                 )
  765.                 <<if ( go ) list_add(&(e->tlist), t);>>
  766.                 )*
  767.             "\}"
  768.         ;
  769.         <<CannotContinue=TRUE;>>
  770.  
  771. token    :    <<char *t=NULL, *e=NULL, *a=NULL; int tnum=0;>>
  772.             "#token"
  773.             {    TokenTerm  <<t=mystrdup(LATEXT(1));>>
  774.                 {    "=" "[0-9]+"        /* define the token type number */
  775.                     <<tnum = atoi(LATEXT(1));>>
  776.                 }
  777.             }
  778.             { QuotedTerm <<e=mystrdup(LATEXT(1));>> }
  779.             {    Action
  780.                 <<
  781.                     a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  782.                     require(a!=NULL, "rule token: cannot allocate action");
  783.                     strcpy(a, LATEXT(1));
  784.                 >>
  785.             }
  786.             <<chkToken(t, e, a, tnum);>>
  787.         ;
  788.         <<CannotContinue=TRUE;>>
  789.  
  790. block[set *toksrefd, set *rulesrefd]
  791.         :    <<
  792.             Graph g, b;
  793.             *$toksrefd = empty;
  794.             *$rulesrefd = empty;
  795.             set_clr(AST_nodes_refd_in_actions);
  796.             >>
  797.             alt[toksrefd,rulesrefd]        <<b = g = $1;>>
  798.             <<
  799.             if ( ((Junction *)g.left)->p1->ntype == nAction )
  800.             {
  801.                 if ( !((ActionNode *)(((Junction *)g.left)->p1))->is_predicate )
  802.                 {
  803.                     ((ActionNode *)(((Junction *)g.left)->p1))->init_action = TRUE;
  804.                 }
  805.             }
  806.             >>
  807.             (    "\|"
  808.                 alt[toksrefd,rulesrefd]        <<g = Or(g, $2);>>
  809.             )*
  810.             <<$0 = b;>>
  811.         ;
  812.         <<CannotContinue=TRUE;>>
  813.  
  814. alt[set *toksrefd, set *rulesrefd]
  815.         :    <<int n=0,ne=0; Graph g; int e_num=0, not=0;
  816.             int first_on_line = 1;
  817.             g.left=NULL; g.right=NULL;
  818.             >>
  819.             (    <<int tok;>>
  820.                 <<tok = LA(1);>>
  821.                 { <<not=0;>> "\~" <<not=1;>> }
  822.                 element[not, first_on_line]
  823.                 <<if ( tok!=Action && tok!=Pred ) first_on_line = 0;>>
  824.                 <<
  825.                 if ( $2.left!=NULL ) {
  826.                     g = Cat(g, $2);
  827.                     n++;
  828.                     if ( tok!=Action && tok!=Pred ) e_num++;
  829.                     /* record record number of all rule and token refs */
  830.                     if ( tok==TokenTerm||tok==QuotedTerm||tok==WildCard ) {
  831.                         ((TokNode *)((Junction *)$2.left)->p1)->elnum = e_num;
  832.                         set_orel(e_num, $toksrefd);
  833.                     }
  834.                     else if ( tok==NonTerminal ) {
  835.                         ((RuleRefNode *)((Junction *)$2.left)->p1)->elnum = e_num;
  836.                         set_orel(e_num, $rulesrefd);
  837.                     }
  838.                 }
  839.                 >>
  840.             )*
  841.             <<if ( n == 0 ) g = emptyAlt();
  842.               $0 = g;
  843.             >>
  844.         ;
  845.         <<CannotContinue=TRUE;>>
  846.  
  847. element[int not, int first_on_line]
  848.         :    <<
  849.             set toksrefd, rulesrefd;
  850.             TermEntry *term;
  851.             TokNode *p=NULL; RuleRefNode *q; int approx=0;
  852.             >>
  853.             TokenTerm
  854.             <<
  855.             term = (TermEntry *) hash_get(Tname, LATEXT(1));
  856.             if ( term==NULL && UserDefdTokens ) {
  857.                 err("implicit token definition not allowed with #tokdefs");
  858.                 $0.left = $0.right = NULL;
  859.             }
  860.             else {
  861.                 $0 = buildToken(LATEXT(1)); p=((TokNode *)((Junction *)$0.left)->p1);
  862.                 term = (TermEntry *) hash_get(Tname, LATEXT(1));
  863.                 require( term!= NULL, "hash table mechanism is broken");
  864.                 p->tclass = term->tclass;
  865.                 p->complement = $not;
  866.             }
  867.             >>
  868.             {    ".."
  869.                 (    QuotedTerm
  870.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  871.                 |    TokenTerm
  872.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  873.                 )
  874.             }
  875.             <<
  876.             if ( p!=NULL && (p->upper_range!=0 || p->tclass || $not) )
  877.                 list_add(&MetaTokenNodes, (void *)p);
  878.             >>
  879.             (    "^"    <<if ( p!=NULL ) p->astnode=ASTroot;>>
  880.             |        <<if ( p!=NULL ) p->astnode=ASTchild;>>
  881.             |    "!" <<if ( p!=NULL ) p->astnode=ASTexclude;>>
  882.             )
  883.         |    QuotedTerm
  884.             <<
  885.             term = (TermEntry *) hash_get(Texpr, LATEXT(1));
  886.             if ( term==NULL && UserDefdTokens ) {
  887.                 err("implicit token definition not allowed with #tokdefs");
  888.                 $0.left = $0.right = NULL;
  889.             }
  890.             else {
  891.                 $0 = buildToken(LATEXT(1)); p=((TokNode *)((Junction *)$0.left)->p1);
  892.                 p->complement = $not;
  893.             }
  894.             >>
  895.             {    ".."
  896.                 (    QuotedTerm
  897.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  898.                 |    TokenTerm
  899.                     <<if ( p!=NULL ) setUpperRange(p, LATEXT(1));>>
  900.                 )
  901.             }
  902.             (    "^"    <<if ( p!=NULL ) p->astnode=ASTroot;>>
  903.             |        <<if ( p!=NULL ) p->astnode=ASTchild;>>
  904.             |    "!" <<if ( p!=NULL ) p->astnode=ASTexclude;>>
  905.             )
  906.             <<
  907.             if ( p!=NULL && (p->upper_range!=0 || p->tclass || $not) )
  908.                 list_add(&MetaTokenNodes, (void *)p);
  909.             >>
  910.         |    <<if ( $not ) warn("~ WILDCARD is an undefined operation (implies 'nothing')");>>
  911.             "."
  912.             <<$0 = buildWildCard(LATEXT(1)); p=((TokNode *)((Junction *)$0.left)->p1);>>
  913.             (    "^"    <<p->astnode=ASTroot;>>
  914.             |        <<p->astnode=ASTchild;>>
  915.             |    "!" <<p->astnode=ASTexclude;>>
  916.             )
  917.             <<list_add(&MetaTokenNodes, (void *)p);>>
  918.         |    <<if ( $not ) warn("~ NONTERMINAL is an undefined operation");>>
  919.             NonTerminal
  920.             <<$0 = buildRuleRef(LATEXT(1));>>
  921.             { "!" <<q = (RuleRefNode *) ((Junction *)$$.left)->p1;
  922.                     q->astnode=ASTexclude;>>
  923.             }
  924.             {    {"\<"}
  925.                 PassAction <<addParm(((Junction *)$$.left)->p1, LATEXT(1));>>
  926.             }
  927.             {    <<char *a; RuleRefNode *rr=(RuleRefNode *) ((Junction *)$$.left)->p1;
  928.                   >>
  929.                 "\>"
  930.                 PassAction
  931.                 <<
  932.                     a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  933.                     require(a!=NULL, "rule element: cannot allocate assignment");
  934.                     strcpy(a, LATEXT(1));
  935.                     rr->assign = a;
  936.                 >>
  937.             }
  938.         |    <<if ( $not )    warn("~ ACTION is an undefined operation");>>
  939.             Action <<$0 = buildAction(LATEXT(1),action_file,action_line, 0);>>
  940.         |    <<if ( $not )    warn("~ SEMANTIC-PREDICATE is an undefined operation");>>
  941.             Pred   <<$0 = buildAction(LATEXT(1),action_file,action_line, 1);>>
  942.             {    <<char *a; ActionNode *act = (ActionNode *) ((Junction *)$$.left)->p1;>>
  943.                 PassAction
  944.                 <<
  945.                 a = (char *) calloc(strlen(LATEXT(1))+1, sizeof(char));
  946.                 require(a!=NULL, "rule element: cannot allocate predicate fail action");
  947.                 strcpy(a, LATEXT(1));
  948.                 act->pred_fail = a;
  949.                 >>
  950.             }
  951.         |    <<if ( $not )    warn("~ BLOCK is an undefined operation");>>
  952.             <<BlkLevel++;>>
  953.             {    "#pragma"
  954.                 (    "approx" <<approx=LL_k;>>
  955.                 |    "LL(1)"  <<approx = 1;>>
  956.                 |    "LL(2)"  <<approx = 2;>>
  957.                 )
  958.             }
  959.             (    "\(" block[&toksrefd,&rulesrefd]
  960.                                 <<$$ = $2; --BlkLevel;>> "\)"
  961.                 (    "\*"        <<$$ = makeLoop($$,approx);>>
  962.                 |    "\+"        <<$$ = makePlus($$,approx);>>
  963.                 |    "?"            <<$$ = makeBlk($$,approx);
  964.                                   FoundGuessBlk = 1;
  965.                                   ((Junction *) ((Junction *)$$.left)->p1)->guess=1;
  966.                                   if ( !$first_on_line ) {
  967.                                     err("(...)? predicate must be first element of production");
  968.                                   }
  969.                                 >>
  970.                 |                <<$$ = makeBlk($$,approx);>>
  971.                 )
  972.                 <<
  973.                 ((Junction *)((Junction *)$$.left)->p1)->tokrefs = toksrefd;
  974.                 ((Junction *)((Junction *)$$.left)->p1)->rulerefs = rulesrefd;
  975.                 >>
  976.  
  977.                 {    PassAction    <<addParm(((Junction *)$$.left)->p1, LATEXT(1));>>
  978.                 }
  979.             |    "\{"    block[&toksrefd,&rulesrefd]
  980.                         <<$$ = makeOpt($2,approx); --BlkLevel;>>
  981.                 "\}"
  982.                 <<
  983.                 ((Junction *)((Junction *)$$.left)->p1)->tokrefs = toksrefd;
  984.                 ((Junction *)((Junction *)$$.left)->p1)->rulerefs = rulesrefd;
  985.                 >>
  986.                 {    PassAction    <<addParm(((Junction *)$$.left)->p1, LATEXT(1));>>
  987.                 }
  988.             )
  989.  
  990. /* Error catching alternatives */
  991.         |    ":"        <<warn(eMsg1("missing ';' on rule %s", CurRule));
  992.                       CannotContinue=TRUE;>>
  993.         |    "\*"    <<warn("don't you want a ')' with that '*'?"); CannotContinue=TRUE;>>
  994.         |    "\+"    <<warn("don't you want a ')' with that '+'?"); CannotContinue=TRUE;>>
  995.         |    "\>"    <<warn("'>' can only appear after a nonterminal"); CannotContinue=TRUE;>>
  996.         |    PassAction <<warn("[...] out of context 'rule > [...]'");
  997.                          CannotContinue=TRUE;>>
  998.         ;
  999.         <<CannotContinue=TRUE;>>
  1000.  
  1001. #token NonTerminal        "[a-z] [A-Za-z0-9_]*"
  1002. #token TokenTerm        "[A-Z] [A-Za-z0-9_]*"
  1003. #token "#[A-Za-z0-9_]*"    <<warn(eMsg1("unknown meta-op: %s",LATEXT(1))); zzskip(); >>
  1004.  
  1005. #lexclass PARSE_ENUM_FILE
  1006.  
  1007. #token "[\t\ ]+"            << zzskip(); >>                /* Ignore White */
  1008. #token "[\n\r]"                << zzline++; zzskip(); >>    /* Track Line # */
  1009. #token "//"                    << zzmode(TOK_DEF_CPP_COMMENTS); zzmore(); >>
  1010. #token "/\*"                << zzmode(TOK_DEF_COMMENTS); zzmore(); >>
  1011. #token "@"                    << ; >>
  1012.  
  1013. enum_file[char *fname]
  1014.     :    ( enum_def[$fname] )*
  1015.     |    defines[$fname]
  1016.     ;
  1017.  
  1018. defines[char *fname]
  1019.     :    <<int v,maxt= -1; char *t;>>
  1020.         (
  1021.             "#define" ID
  1022.             <<t = mystrdup(LATEXT(1));>>
  1023.             INT
  1024.             <<
  1025.             v = atoi(LATEXT(1));
  1026. /*            fprintf(stderr, "#token %s=%d\n", t, v); */
  1027.             TokenNum = v;
  1028.             if ( v>maxt ) maxt=v;
  1029.             if ( Tnum( t ) == 0 ) addForcedTname( t, v );
  1030.             else {
  1031.                 warnFL(eMsg1("redefinition of token %s; ignored",t),$fname,zzline);
  1032.             }
  1033.             >>
  1034.         )*
  1035.         <<TokenNum = maxt + 1;>>
  1036.     ;
  1037.  
  1038. enum_def[char *fname]
  1039.     :    <<int v= -1; char *t;>>
  1040.         "enum" ID
  1041.         "\{"
  1042.             ID
  1043.             <<t = mystrdup(LATEXT(1));>>
  1044.             (    "=" INT    <<v=atoi(LATEXT(1));>>
  1045.             |            <<v++;>>
  1046.             )
  1047.             <<
  1048. /*            fprintf(stderr, "#token %s=%d\n", t, v);*/
  1049.             TokenNum = v;
  1050.             if ( Tnum( t ) == 0 ) addForcedTname( t, v );
  1051.             else {
  1052.                 warnFL(eMsg1("redefinition of token %s; ignored",t),$fname,zzline);
  1053.             }
  1054.             >>
  1055.             (    ","
  1056.                 {    ID
  1057.                     <<t = mystrdup(LATEXT(1));>>
  1058.                     (    "=" INT    <<v=atoi(LATEXT(1));>>
  1059.                     |            <<v++;>>
  1060.                     )
  1061.                     <<
  1062. /*                    fprintf(stderr, "#token %s=%d\n", t, v);*/
  1063.                     TokenNum = v;
  1064.                     if ( Tnum( t ) == 0 ) addForcedTname( t, v );
  1065.                     else {
  1066.                         warnFL(eMsg1("redefinition of token %s; ignored",t),$fname,zzline);
  1067.                     }
  1068.                     >>
  1069.                 }
  1070.             )*
  1071.         "\}"
  1072.         ";"
  1073.         <<TokenNum++;>>
  1074.     ;
  1075.  
  1076. #token INT    "[0-9]+"
  1077. #token ID    "[A-Z][_a-zA-Z0-9]*"
  1078.  
  1079. #lexclass START
  1080.  
  1081. <<
  1082. /* semantics of #token */
  1083. static void
  1084. #ifdef __STDC__
  1085. chkToken(char *t, char *e, char *a, int tnum)
  1086. #else
  1087. chkToken(t,e,a,tnum)
  1088. char *t, *e, *a;
  1089. int tnum;
  1090. #endif
  1091. {
  1092.     TermEntry *p;
  1093.  
  1094.     /* check to see that they don't try to redefine a token as a token class */
  1095.     if ( t!=NULL ) {
  1096.         p = (TermEntry *) hash_get(Tname, t);
  1097.         if ( p!=NULL && p->classname ) {
  1098.             err(eMsg1("redefinition of #tokclass '%s' to #token not allowed; ignored",t));
  1099.             if ( a!=NULL ) free((char *)a);
  1100.             return;
  1101.         }
  1102.     }
  1103.  
  1104.     if ( t==NULL && e==NULL ) {            /* none found */
  1105.         err("#token requires at least token name or rexpr");
  1106.     }
  1107.     else if ( t!=NULL && e!=NULL ) {    /* both found */
  1108.         if ( UserDefdTokens ) {            /* if #tokdefs, must not define new */
  1109.             p = (TermEntry *) hash_get(Tname, t);
  1110.             if ( p==NULL ) {
  1111.                 err(eMsg1("#token definition '%s' not allowed with #tokdefs; ignored",t));
  1112.                 return;
  1113.             }
  1114.         }
  1115.         Tklink(t, e);
  1116.         if ( a!=NULL ) {
  1117.             if ( hasAction(e) ) {
  1118.                 err(eMsg1("redefinition of action for %s; ignored",e));
  1119.             }
  1120.             else setHasAction(e, a);
  1121.         }
  1122.     }
  1123.     else if ( t!=NULL ) {                /* only one found */
  1124.         if ( UserDefdTokens ) {
  1125.             err(eMsg1("#token definition '%s' not allowed with #tokdefs; ignored",t));
  1126.             return;
  1127.         }
  1128.         if ( Tnum( t ) == 0 ) addTname( t );
  1129.         else {
  1130.             err(eMsg1("redefinition of token %s; ignored",t));
  1131.         }
  1132.         if ( a!=NULL ) {
  1133.             err(eMsg1("action cannot be attached to a token name (%s); ignored",t));
  1134.             free((char *)a);
  1135.         }
  1136.     }
  1137.     else if ( e!=NULL ) {
  1138.         if ( Tnum( e ) == 0 ) addTexpr( e );
  1139.         else {
  1140.             if ( hasAction(e) ) {
  1141.                 err(eMsg1("redefinition of action for expr %s; ignored",e));
  1142.             }
  1143.             else if ( a==NULL ) {
  1144.                 err(eMsg1("redefinition of expr %s; ignored",e));
  1145.             }
  1146.         }
  1147.         if ( a!=NULL ) setHasAction(e, a);
  1148.     }
  1149.  
  1150.     /* if a token type number was specified, then add the token ID and 'tnum'
  1151.      * pair to the ForcedTokens list.  (only applies if an id was given)
  1152.      */
  1153.     if ( t!=NULL && tnum>0 )
  1154.     {
  1155.         if ( set_el(tnum, reserved_positions) )
  1156.         {
  1157.             err(eMsgd("a token has already been forced to token number %d; ignored", tnum));
  1158.         }
  1159.         else
  1160.         {
  1161.             list_add(&ForcedTokens, newForcedToken(t,tnum));
  1162.             set_orel(tnum, &reserved_positions);
  1163.         }
  1164.     }
  1165. }
  1166. >>
  1167.  
  1168. <<
  1169. /* ANTLR-specific syntax error message generator 
  1170.  * (define USER_ZZSYN when compiling so don't get 2 definitions)
  1171.  */
  1172. void
  1173. #ifdef __STDC__
  1174. zzsyn(char *text, int tok, char *egroup, SetWordType *eset, int etok, int k, char *bad_text)
  1175. #else
  1176. zzsyn(text, tok, egroup, eset, etok, k, bad_text)
  1177. char *text, *egroup, *bad_text;
  1178. int tok;
  1179. int etok;
  1180. int k;
  1181. SetWordType *eset;
  1182. #endif
  1183. {
  1184.     fprintf(stderr, ErrHdr, FileStr[CurFile]!=NULL?FileStr[CurFile]:"stdin", zzline);
  1185.     fprintf(stderr, " syntax error at \"%s\"", (tok==zzEOF_TOKEN)?"EOF":text);
  1186.     if ( !etok && !eset ) {fprintf(stderr, "\n"); return;}
  1187.     if ( k==1 ) fprintf(stderr, " missing");
  1188.     else
  1189.     {
  1190.         fprintf(stderr, "; \"%s\" not", bad_text);
  1191.         if ( zzset_deg(eset)>1 ) fprintf(stderr, " in");
  1192.     }
  1193.     if ( zzset_deg(eset)>0 ) zzedecode(eset);
  1194.     else fprintf(stderr, " %s", zztokens[etok]);
  1195.     if ( strlen(egroup) > 0 ) fprintf(stderr, " in %s", egroup);
  1196.     fprintf(stderr, "\n");
  1197. }
  1198. >>
  1199.